package com.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * 一个UDP接收端，它会监听指定端口，接收数据报，
 * 然后将收到的消息原样发回给发送方。
 */
public class UDPReceiver {

    public static void main(String[] args) {
        final int PORT = 9876; // 定义监听的端口号
        final int BUFFER_SIZE = 1024; // 定义缓冲区大小

        // 使用 try-with-resources 语句，可以自动关闭 DatagramSocket
        try (DatagramSocket socket = new DatagramSocket(PORT)) {
            System.out.println("✅ UDP接收端已启动，正在端口 " + PORT + " 上等待数据...");

            // 创建一个字节数组作为接收数据的缓冲区
            byte[] buffer = new byte[BUFFER_SIZE];

            // 无限循环，持续接收数据
            while (true) {
                // 1. 准备一个空的数据报包(DatagramPacket)来接收数据
                DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);

                // 2. 调用 receive 方法，程序会在此阻塞，直到收到一个数据报
                socket.receive(receivePacket);

                // 3. 从数据报中解析收到的信息
                // 注意：必须使用 packet.getLength() 来获取实际接收到的数据长度
                String receivedMessage = new String(receivePacket.getData(), 0, receivePacket.getLength(), "UTF-8");
                InetAddress senderAddress = receivePacket.getAddress(); // 获取发送方的IP地址
                int senderPort = receivePacket.getPort(); // 获取发送方的端口号

                System.out.println("⬅️ 收到来自 " + senderAddress.getHostAddress() + ":" + senderPort + " 的消息: " + receivedMessage);

                // 如果收到 "bye"，则退出循环，程序结束
                if ("bye".equalsIgnoreCase(receivedMessage.trim())) {
                    System.out.println("❌ 接收到 'bye'，接收端即将关闭。");
                    break;
                }

                // 4. 准备要发送回去的数据报 (回声)
                byte[] sendData = receivedMessage.getBytes("UTF-8");
                DatagramPacket sendPacket = new DatagramPacket(
                        sendData,
                        sendData.length,
                        senderAddress, // 目标IP：就是刚刚那个发送方的IP
                        senderPort     // 目标端口：就是刚刚那个发送方的端口
                );

                // 5. 发送回声数据报
                socket.send(sendPacket);
                System.out.println("➡️ 已将回声发回给 " + senderAddress.getHostAddress() + ":" + senderPort);
            }

        } catch (SocketException e) {
            System.err.println("Socket错误: " + e.getMessage());
        } catch (IOException e) {
            System.err.println("I/O错误: " + e.getMessage());
        } finally {
            System.out.println("⏹️ UDP接收端已关闭。");
        }
    }
}
